#include "timer.h"


void* sending_thread(void* arg){
    tju_tcp_t* sock= (tju_tcp_t*)arg;
    
    while(1){
        if (sock->window.wnd_send->window_size\
            &&sock->have_send_len < sock->sending_len\
            &&(sock->window.wnd_send->nextseq - sock->window.wnd_send->base) < sock->window.wnd_send->window_size\
            &&!sock->is_retransing){

            uint32_t wnd_size = sock->window.wnd_send->window_size;
            uint32_t wnd_ack_cnt = sock->window.wnd_send->ack_cnt;
            uint32_t wnd_base = sock->window.wnd_send->base;
            uint32_t wnd_nextseq = sock->window.wnd_send->nextseq;
            
            pthread_mutex_lock(&sock->send_lock); //加锁
            // 发送数据(发送能发的所有数据)
            uint32_t tmp_len = min(sock->sending_len, wnd_ack_cnt + wnd_size);
            while(sock->have_send_len < tmp_len){
                char* data = sock->sending_buf + sock->have_send_len;
                uint32_t dlen;   //数据长度
                uint32_t plen;   //数据包长度
                if((tmp_len - sock->have_send_len) <= MAX_DLEN){//一次性发完
                    dlen = tmp_len - sock->have_send_len;
                    plen = DEFAULT_HEADER_LEN + dlen;

                    char* packet = create_packet_buf(sock->established_local_addr.port,\ 
                        sock->established_remote_addr.port, \
                        wnd_nextseq, 0, DEFAULT_HEADER_LEN, plen, \
                        NO_FLAG, 1, 0, data, dlen);
                    
                    sendToLayer3(packet, plen);
                    _SEND_LOG_(packet);
                    free(packet);
                }else{
                    dlen = MAX_DLEN;
                    plen = DEFAULT_HEADER_LEN + dlen;
                    char* packet = create_packet_buf(sock->established_local_addr.port,\ 
                        sock->established_remote_addr.port, \
                        wnd_nextseq, 0, DEFAULT_HEADER_LEN, plen, \
                        NO_FLAG, 1, 0, data, dlen);
                    sendToLayer3(packet, plen);
                    _SEND_LOG_(packet);
                    free(packet);
                }
                printf("首次发送 %d 字节大小的报文 seq = %d\n", dlen, wnd_nextseq);

                //计算SampleRTT
                if(!sock->window.wnd_send->is_estimating_rtt){
                    sock->window.wnd_send->is_estimating_rtt = TRUE;
                    gettimeofday(&sock->window.wnd_send->send_time, NULL);
                    sock->window.wnd_send->rtt_expect_ack = wnd_nextseq + dlen;
                }

                //发送窗口的第一个包，启动计时器
                if(wnd_base == wnd_nextseq){
                    startTimer(sock);
                    sock->is_retransing = TRUE;
                }

                //更新缓冲区和临时参数
                sock->have_send_len += dlen;
                wnd_nextseq += dlen;

            }
            
            //更新窗口参数
            sock->window.wnd_send->nextseq = wnd_nextseq;
            pthread_mutex_unlock(&sock->send_lock); //解锁
        }
    }
}

//is_retransing, RETRANS, TIMEOUT_FLAG
void* retrans_thread(void* arg){
    tju_tcp_t* sock = (tju_tcp_t*)arg;

    while(1){
        if(RETRANS){

            //发送零窗口探测报文
            if(sock->window.wnd_send->window_size == 0){
                char* packet = create_packet_buf(sock->established_local_addr.port,\ 
                    sock->established_remote_addr.port, \
                    sock->window.wnd_send->nextseq, 0, DEFAULT_HEADER_LEN, DEFAULT_HEADER_LEN, \
                    NO_FLAG, 1, 0, NULL, 0);
                sendToLayer3(packet, DEFAULT_HEADER_LEN);
                _SEND_LOG_(packet);
                free(packet);
                startTimer(sock);
                continue;
            }

            //未处于重传状态
            if(!sock->is_retransing){
                RETRANS = FALSE;
                if(sock->window.wnd_send->ack_cnt < sock->have_send_len){
                    printf("发送窗口还有未收到确认的数据\n");
                    RETRANS = TRUE;
                    sock->is_retransing = TRUE;
                }
                continue;
            }
            

            pthread_mutex_lock(&(sock->send_lock)); //加锁
            if(TIMEOUT_FLAG){
                //变为慢启动,ssthresh = cwnd/2, 拥塞窗口变为一个MSS, 更新发送窗口
                sock->window.wnd_send->window_status = SLOW_START;
                sock->window.wnd_send->window_size = MAX_DLEN;
                _CWND_LOG_(sock,TIMEOUT);
                sock->window.wnd_send->ssthresh = sock->window.wnd_send->cwnd >> 1;
                sock->window.wnd_send->window_size = min(sock->window.wnd_send->cwnd, sock->window.wnd_send->rwnd);
                _SWND_LOG_(sock);
            }

            //临时变量
            uint32_t wnd_ack_cnt = sock->window.wnd_send->ack_cnt;
            uint32_t have_send_len = sock->have_send_len;
            uint32_t wnd_base = sock->window.wnd_send->base;

            while(wnd_ack_cnt < have_send_len){
                //重传数据不用检查
                char* data = sock->sending_buf + wnd_ack_cnt;
                uint32_t dlen;
                if((have_send_len - wnd_ack_cnt) <= MAX_DLEN){
                    dlen = (have_send_len - wnd_ack_cnt);
                    char* packet = create_packet_buf(sock->established_local_addr.port,\ 
                        sock->established_remote_addr.port, \
                        wnd_ack_cnt, 0, DEFAULT_HEADER_LEN, DEFAULT_HEADER_LEN, \
                        NO_FLAG, 1, 0, data, dlen);
                    sendToLayer3(packet, DEFAULT_HEADER_LEN + dlen);
                    _SEND_LOG_(packet);
                    free(packet);
                }else{
                    dlen = MAX_DLEN;
                    char* packet = create_packet_buf(sock->established_local_addr.port,\ 
                        sock->established_remote_addr.port, \
                        wnd_ack_cnt, 0, DEFAULT_HEADER_LEN, DEFAULT_HEADER_LEN, \
                        NO_FLAG, 1, 0, data, dlen);
                    sendToLayer3(packet, DEFAULT_HEADER_LEN + dlen);
                    _SEND_LOG_(packet);
                    free(packet);
                }
                printf("重传 %d 字节大小的报文 seq = %d\n", dlen, wnd_base);

                //启动计时器(如果是重传窗口的第一个包)
                if(wnd_ack_cnt == sock->window.wnd_send->ack_cnt){
                    startTimer(sock);
                    sock->is_retransing = TRUE;
                }

                wnd_ack_cnt += dlen;
                wnd_base += dlen;

            }
            RETRANS = FALSE;
            sock->is_retransing = FALSE;
            pthread_mutex_unlock(&sock->send_lock); //解锁
        }

    }
    
}

void startTimer(tju_tcp_t *sock){
    struct itimerval tick; 
    RETRANS = FALSE;
    TIMEOUT_FLAG = FALSE;
    
    //确定超时重传间隔
    memset(&tick, 0, sizeof(tick));
    memcpy(&tick, &sock->window.wnd_send->timeout, sizeof(tick));

    //开启计时器
    if(setitimer(ITIMER_REAL, &tick, NULL)){
        perror("setitimer failed");
    }
}

void timeout_handler(int signo){ 
    TIMEOUT_FLAG = TRUE;
    RETRANS = TRUE;
}

void stopTimer(void){
    struct itimerval tick; 
    memset(&tick, 0, sizeof(tick));
    if(setitimer(ITIMER_REAL, &tick, NULL)){
        perror("setitimer failed");
    }
}

void CalTimeout(tju_tcp_t *sock) { 
    //获取当前时间和发送时间
    struct timeval local_time;
    gettimeofday(&local_time, NULL);
    struct timeval send_time = sock->window.wnd_send->send_time;
    //计算SampleRTT
    long sampleRTT = (local_time.tv_sec - send_time.tv_sec) * 1000000 + (local_time.tv_usec - send_time.tv_usec);
    //计算期望的RTT
    sock->window.wnd_send->estmated_rtt = 0.875 * sock->window.wnd_send->estmated_rtt + 0.125 * sampleRTT;
    //计算RTT的偏差
    sock->window.wnd_send->dev_rtt = 0.75 * sock->window.wnd_send->dev_rtt + 0.25 * abs(sampleRTT - sock->window.wnd_send->estmated_rtt);
    //计算超时重传间隔RTO
    sock->window.wnd_send->timeout.it_value.tv_usec = sock->window.wnd_send->estmated_rtt + 4 * sock->window.wnd_send->dev_rtt;
    _RTTS_LOG_(sock,sampleRTT);

}

